home *** CD-ROM | disk | FTP | other *** search
- ; DISKSCAN.ASM -- Checks out disk by reading sectors
-
- ; --------------------------------------------------
-
-
-
- CSEG Segment
-
- Assume CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
-
- Org 100h
-
- Entry: Jmp Begin
-
-
-
- ; All Data
-
- ; --------
-
- db ' Copyright 1986 Ziff-Davis Publishing Co.'
-
- db ' Programmed by Charles Petzold '
-
- DriveError db 'Invalid Drive$'
-
- DosVersErr db 'Needs DOS 2.0+$'
-
- MemoryError db 'Needs 64K$'
-
- ReadSegment dw ?
-
- DriveNum db ?
-
- DiskBlock db 18 dup (?)
-
- TotalSectors dw ?
-
- SectorsIn64K dw ?
-
- StartSector dw 0
-
- SectorLabel2 db 9,'Sector $'
-
- SectorLabel db 13,'Sectors $'
-
- DashLabel db ' - $'
-
- ErrorLabel db ': Error!'
-
- CRLF db 13,10,'$'
-
- ErrorAddr dw Err0,Err1,Err2,Err3,Err4,Err5,Err6,Err7
-
- dw Err8,Err9,ErrA,ErrB,ErrC,ErrD,ErrD,ErrD
-
- Err0 db 'Write Protect$'
-
- Err1 db 'Unknown Unit$'
-
- Err2 db 'Drive Not Ready$'
-
- Err3 db 'Unknown Command$'
-
- Err4 db 'CRC Error$'
-
- Err5 db 'Request Length$'
-
- Err6 db 'Seek Error$'
-
- Err7 db 'Unknown Media$'
-
- Err8 db 'Sector Not Found$'
-
- Err9 db 'No Paper$'
-
- ErrA db 'Write Fault$'
-
- ErrB db 'Read Fault$'
-
- ErrC db 'General Failure$'
-
- ErrD db 'Undocumented Error$'
-
- BootSectMsg db 'Boot Sector$'
-
- RootDirMsg db 'Root Directory$'
-
- BadFatMsg db 'File Alloc. Table$'
-
- InUseMsg db 'Used by file$'
-
- NotInUseMsg db 'Unallocated$'
-
- BadFlagMsg db 'Flagged as bad$'
-
- FatReadMsg db "Can't Read FAT$"
-
- Divisors dw 10000, 1000, 100, 10, 1 ; For decimal conversion
-
-
-
- ; Check Drive Parameter, DOS Version, and Enough Memory
-
- ; -----------------------------------------------------
-
-
-
- ErrorExit: Mov AH,9 ; Write error message
-
- Int 21h ; through DOS
-
- Int 20h ; And terminate
-
-
-
- Begin: Mov DX, Offset DriveError ; Possible message
-
- Or AL, AL ; Check Drive Validity Byte
-
- Jnz ErrorExit ; If not zero, invalid drive
-
- Mov DX, Offset DosVersErr ; Possible message
-
- Mov AH, 30h
-
- Int 21h ; Get DOS Version Number
-
- Cmp AL, 2 ; Check for 2.0 or later
-
- Jb ErrorExit ; If not, terminate with message
-
- Mov DX, Offset MemoryError ; Possible error message
-
- Mov BX, 256+Offset EndProg ; Set beyond program
-
- Mov SP, BX ; Move stack closer to code
-
- Add BX, 15 ; Add 15 to round up
-
- Mov CL, 4 ; Divide BX by 16
-
- Shr BX, CL
-
- Mov AH, 4Ah ; Free allocated memory
-
- Int 21h ; by calling DOS Set Block
-
- Jc ErrorExit ; Terminate on error
-
- Mov BX, 1000h ; Ask for 64K bytes
-
- Mov AH, 48h ; by using DOS
-
- Int 21h ; Allocate Memory call
-
- Jc ErrorExit ; Terminate on error
-
- Mov [ReadSegment], AX ; Save segment of memory block
-
-
-
- ; Get Disk Information From DOS
-
- ; -----------------------------
-
-
-
- Mov DL, DS:[005Ch] ; Get Drive Parameter
-
- Push DS ; Save DS
-
- Mov AH, 32h ; Call DOS to
-
- Int 21h ; get DOS Disk Block (DS:BX)
-
- Mov SI, BX ; Now DS:SI points to Disk Block
-
- Mov DI, Offset DiskBlock ; DI points to destination
-
- Mov CX, 18 ; 18 bytes to copy'
-
- Cld ; Forward direction
-
- Rep Movsb ; Move 'em in
-
- Pop DS ; Get back DS
-
- Mov BX, Offset DiskBlock ; BX to address Disk Block
-
- Mov DX, 1 ; Set DX:AX to 65,536
-
- Sub AX, AX
-
- Div Word Ptr [BX + 2] ; Divide by Bytes Per Sector
-
- Mov [SectorsIn64K], AX ; Save that values
-
- Mov AX, [BX + 13] ; Last Cluster Number
-
- Dec AX ; AX = Number of Clusters
-
- Mov CL, [BX + 5] ; Cluster to Sector Shift
-
- Shl AX, CL ; AX = Number Data Sectors
-
- Add AX, [BX + 11] ; Add First Data Sector
-
- Mov [TotalSectors], AX ; AX = Number Total Sectors
-
- Mov AL, DS:[005Ch] ; Drive Number (0=def, 1=A)
-
- Dec AL ; Make it 0=A, 1=B
-
- Jns GotDriveNumber ; If no sign, not default drive
-
- Mov AH, 19h ; Get current disk
-
- Int 21h ; by calling DOS
-
-
-
- GotDriveNumber: Mov [DriveNum], AL ; Save Drive Number (0=A, 1=B)
-
-
-
- ; Start Reading
-
- ; -------------
-
-
-
- MainLoop: Mov DX, Offset SectorLabel ; String to display on screen
-
- Call StringWrite ; Display it
-
- Mov AX, [StartSector] ; Starting sector number
-
- Call WordWrite ; Display number on screen
-
- Mov DX, Offset DashLabel ; String containing a dash
-
- Call StringWrite ; Display it on the screen
-
- Mov CX, [SectorsIn64K] ; Number of sectors to read
-
- Add AX, CX ; Add it to starting sector
-
- Jc NumRecalc
-
- Cmp AX, [TotalSectors] ; See if bigger than total
-
- Jbe NumSectorsOK ; If so, proceed
-
-
-
- NumRecalc: Mov AX, [TotalSectors] ; Otherwise get total sectors
-
- Mov CX, AX ; Move it to CX also
-
- Sub CX, [StartSector] ; Now CX = sectors to read
-
-
-
- NumSectorsOK: Dec AX ; AX = last sector to read
-
- Call WordWrite ; Display it on screen
-
- Call ReadSectors ; Read the sectors
-
- Jnc NextSectors ; If no error, skip detail
-
- Call ReadSectors ; Repeat read
-
- Jnc NextSectors ; If still no error, skip
-
-
-
- DiskError: Mov DX, Offset ErrorLabel ; String saying "Error!"
-
- Call StringWrite ; Display it on screen
-
-
-
- ErrorLoop: Push CX ; Now save previous number
-
- Mov CX, 1 ; So we can read one at a time
-
- Call ReadSectors ; Read one sector
-
- Jnc NoError ; If no error, proceed
-
- Mov BL, AL ; Save error code
-
- Mov DX, Offset SectorLabel2 ; String with "Sector "
-
- Call StringWrite ; Display it on screen
-
- Mov AX, [StartSector] ; The sector we just read
-
- Call WordWrite ; Display it on screen
-
- Mov DX, Offset DashLabel ; String with a dash
-
- Call StringWrite ; Display it on screen
-
- And BL, 0Fh ; Blank out error top bits
-
- Sub BH, BH ; Now BX is error code
-
- Add BX, BX ; Double it for word access
-
- Mov DX, [ErrorAddr + BX] ; Get address of message
-
- Call StringWrite ; Display message on screen
-
- Call FindSector ; See where sector is
-
- Mov DX, Offset CRLF ; String for new line
-
- Call StringWrite ; Do carriage ret & line feed
-
-
-
- NoError: Inc [StartSector] ; Kick up the start sector
-
- Pop CX ; Get back counter
-
- Loop ErrorLoop ; And read next sector
-
- Mov AX, [StartSector] ; Sector of next group
-
- Jmp Short CheckFinish ; Check if at end yet
-
-
-
- NextSectors: Mov AX, [StartSector] ; For no error, increment
-
- Add AX, [SectorsIn64K] ; StartSector for next group
-
- Jc Terminate ; (If overflow, terminate)
-
- Mov [StartSector], AX ; And save it
-
-
-
- CheckFinish: Cmp AX, [TotalSectors] ; See if at then end
-
- Jae Terminate ; If so, just terminate
-
- Jmp MainLoop ; If not, do it again
-
-
-
- Terminate: Int 20h ; Terminate
-
-
-
- ; Find Sector in FAT to see if used by file, etc.
-
- ; -----------------------------------------------
-
-
-
- FindSector: Mov DX, Offset DashLabel ; Print dash
-
- Call StringWrite
-
- Mov AX, [StartSector] ; Sector with error
-
- Mov DX, Offset BootSectMsg ; Set up message
-
- Cmp AX, Word Ptr [DiskBlock + 6] ; See if sector boot
-
- Jb PrintMsg ; If so, print as such
-
- Mov DX, Offset BadFatMsg ; Set up message
-
- Cmp AX, Word Ptr [DiskBlock + 16] ; See if sector in FAT
-
- Jb PrintMsg ; If so, print as such
-
- Mov DX, Offset RootDirMsg ; Set up message
-
- Cmp AX, Word Ptr [DiskBlock + 11] ; See if sector in dir
-
- Jb PrintMsg ; If so, print as such
-
- Push [StartSector] ; Save the sector
-
- Mov AX, Word Ptr [DiskBlock + 6] ; Reserved sectors
-
- Mov [StartSector], AX ; Start of first FAT
-
- Mov CL, [DiskBlock + 15] ; Sectors for FAT
-
- Sub CH, CH ; Zero out top byte
-
- Call ReadSectors ; Read in FAT
-
- Pop [StartSector] ; Get back bad sector
-
- Mov DX, Offset FatReadMsg ; Set up possible msg
-
- Jc PrintMsg ; If read error, print
-
- Mov AX, [StartSector] ; Get bad sector
-
- Sub AX, Word Ptr [DiskBlock + 11] ; Subtract data start
-
- Mov CL, [DiskBlock + 5] ; Sector Shift
-
- Shr AX, CL ; Shift the sector
-
- Add AX, 2 ; AX is now cluster
-
- Push ES ; Save ES for awhile
-
- Mov ES, [ReadSegment] ; ES segment of FAT
-
- Cmp Word Ptr [DiskBlock + 13], 0FF0h; 12 or 16-bit FAT?
-
- Jge Fat16Bit ; And jump accordingly
-
- Mov BX, AX ; This is cluster number
-
- Mov SI, AX ; So is this
-
- Shr BX, 1 ; This is one-half cluster
-
- Mov AX, ES:[BX + SI] ; BX + SI = 1.5 CX
-
- Jnc NoShift ; If no CY from shift, got it
-
- Mov CL, 4 ; If CY from shift must
-
- Shr AX, CL ; shift word 4 bits right
-
-
-
- NoShift: Or AX, 0F000h ; Now put 1's in top bits
-
- Cmp AX, 0F000h ; See if zero otherwise
-
- Jmp Short CheckWord ; And continue checking
-
-
-
- Fat16Bit: Mov BX, AX ; This is cluster number
-
- Shl BX, 1 ; Double it
-
- Mov AX, ES:[BX] ; Pull out word from sector
-
- Or AX, AX ; See if zero (unallocated)
-
-
-
- CheckWord: Pop ES ; Get back ES
-
- Mov DX, Offset NotInUseMsg ; Set up possible message
-
- Jz PrintMsg ; If so, print message
-
- Mov DX, Offset BadFlagMsg ; Set up possible message
-
- Cmp AX, 0FFF7h ; See if cluster flagged bad
-
- Jz PrintMsg ; If so, print message
-
- Mov DX, Offset InUseMsg ; If not, cluster is in use
-
-
-
- PrintMsg: Call StringWrite ; Print cluster disposition
-
- Ret ; And return
-
-
-
- ; Read Sectors (CX = Number of Sectors, Return CY and AL for error)
-
- ; -----------------------------------------------------------------
-
-
-
- ReadSectors: Push BX ; Push all needed registers
-
- Push CX
-
- Push DX
-
- Push DS
-
- Mov AL, [DriveNum] ; Get the drive number code
-
- Sub BX, BX ; Buffer address offset
-
- Mov DX, [StartSector] ; Starting Sector
-
- Mov DS, [ReadSegment] ; Buffer address segment
-
- Int 25h ; Absolute Disk Read
-
- Pop BX ; Fix up stack
-
- Pop DS ; Get back registers
-
- Pop DX
-
- Pop CX
-
- Pop BX
-
- Ret ; Return to program
-
-
-
- ; Screen Display Routines
-
- ; -----------------------
-
-
-
- WordWrite: Push AX ; Push some registers
-
- Push BX ; AX contains word to display
-
- Push CX
-
- Push DX
-
- Push SI
-
- Mov SI, Offset Divisors ; SI points to divisors
-
- Mov CX, 4 ; CL counter; CH zero blanker
-
-
-
- WordWriteLoop: Mov BX, [SI] ; Get divisor
-
- Add SI, 2 ; Increment SI for next one
-
- Sub DX, DX ; Prepare for division
-
- Div BX ; Divide DX:AX by BX
-
- Push DX ; Save remainder
-
- Or CH, AL ; See if zero
-
- Jz LeadZero ; If so, do not display it
-
- Add AL, '0' ; Convert number to ASCII
-
- Mov DL, AL ; Print out character
-
- Mov AH, 2 ; by calling DOS
-
- Int 21h
-
-
-
- LeadZero: Pop AX ; Get back remainder
-
- Dec CL ; Decrement counter
-
- Jg WordWriteLoop ; If CL still > 0, do it again
-
- Mov CH, 1 ; No more zero blanking
-
- Jz WordWriteLoop ; Convert last digit to ASCII
-
- Pop SI ; Get back pushed registers
-
- Pop DX
-
- Pop CX
-
- Pop BX
-
- Pop AX
-
- Ret
-
-
-
- StringWrite: Push AX ; Displays string from DX
-
- Mov AH, 9 ; to screen by calling DOS
-
- Int 21h
-
- Pop AX
-
- Ret
-
-
-
- EndProg Label Byte ; End of program
-
- CSEG EndS
-
- End Entry
-